#!/usr/bin/python2.7
'''
	IPCamera Protocol Test Tool

	2011-07-18: create
	2011-07-18: PSIA support
	2011-07-25: add dom parse and print
	2011-07-31: add PSIA url for each xml file
	2011-08-28: fix the empty PUT message parse

'''

import urllib2
import wx
from xml.dom.minidom import parse, parseString
import digest_auth
from urlparse import urlparse
import glob
import os
import re

import wx
class Frame(wx.Frame):
	def __init__(self):
		
		wx.Frame.__init__(self, None, -1, "IPCamera Protocol Test")
		panel = wx.Panel(self)
		
		self.startButton = wx.Button(panel, label="start", size=(40, 30));
		self.Bind(wx.EVT_BUTTON, self.OnButtonClick, self.startButton);

		targetLabel = wx.StaticText(panel, -1, "Target Service:", style=wx.ALIGN_BOTTOM)
		self.target = wx.TextCtrl(panel, -1, "http://159.99.249.146/", size=(300, -1))

		userLabel = wx.StaticText(panel, -1, "User Name", style=wx.ALIGN_CENTER)
		self.user = wx.TextCtrl(panel, -1, "", size=(90, -1))

		passwdLabel = wx.StaticText(panel, -1, "Password", style=wx.ALIGN_CENTER)
		self.passwd = wx.TextCtrl(panel, -1, "", size=(90, -1))

		protocolList = ['PSIA', 'ONVIF']
		self.protocol = wx.RadioBox(panel, -1, "Protocol", (10,10), choices=protocolList);

		self.messageList = []
		self.InitList()
		self.msgChoice = wx.Choice(panel, -1, size=(300, 30), choices=self.messageList)
		self.Bind(wx.EVT_CHOICE, self.OnMsgChoice, self.msgChoice);

		reqLabel = wx.StaticText(panel, -1, "Request:", style=wx.ALIGN_CENTER)
		self.req = wx.TextCtrl(panel, -1, "", size=(350, 600), style=wx.TE_MULTILINE)

		rspLabel = wx.StaticText(panel, -1, "Response:", style=wx.ALIGN_CENTER)
		self.rsp = wx.TextCtrl(panel, -1, "", size=(370, 600), style=wx.TE_MULTILINE)

	#	self.sc = wx.SpinCtrl(panel, -1, "", size=(80, -1));
	#	self.sc.SetRange(1,100);
	#	self.sc.SetValue(1);

		ctlSizer = wx.FlexGridSizer(cols=3, hgap=10, vgap=10)
		ctlSizer.Add(targetLabel, 0, wx.ALIGN_CENTER_VERTICAL)
		ctlSizer.Add(self.target, 0, wx.ALIGN_CENTER_VERTICAL)
		ctlSizer.Add(self.startButton, 0, wx.ALIGN_CENTER_VERTICAL)

		authSizer = wx.FlexGridSizer(cols=6, hgap=10, vgap=10)

		authSizer.Add(userLabel, 0, wx.ALIGN_CENTER_VERTICAL)
		authSizer.Add(self.user, 0, wx.ALIGN_CENTER_VERTICAL)
		authSizer.Add(passwdLabel, 0, wx.ALIGN_CENTER_VERTICAL)
		authSizer.Add(self.passwd, 0, wx.ALIGN_CENTER_VERTICAL)
		authSizer.Add(self.protocol, 0, wx.ALIGN_CENTER_VERTICAL)
		authSizer.Add(self.msgChoice, 0, wx.ALIGN_CENTER_VERTICAL)


		msgSizer = wx.FlexGridSizer(cols=4, hgap=20, vgap=6)
		msgSizer.AddMany([reqLabel, self.req, rspLabel, self.rsp])

		VSizer = wx.BoxSizer(wx.VERTICAL)
		VSizer.Add(ctlSizer, 0, wx.SHAPED, 0)
		VSizer.Add((10,10))
		VSizer.Add(authSizer, 0, wx.SHAPED, 10)
		VSizer.Add((10,10))
		VSizer.Add(msgSizer, 0, wx.SHAPED, 10)

		VSizer.Fit(self)
		
		panel.SetAutoLayout(True)
		panel.SetSizer(VSizer)
		panel.Layout()

	def InitList(self):
		if self.protocol.GetSelection() == 0:
			xmlList = glob.glob("./PSIA/*.xml")
		else:
			xmlList = glob.glob("./ONVIF/*.xml")

		for xmlfile in xmlList:
			print xmlfile
			self.messageList.append(os.path.basename(xmlfile))

	def OnMsgChoice(self, event):
		if self.protocol.GetSelection() == 0:
			xml = self.messageList[self.msgChoice.GetCurrentSelection()];
			print xml
			if (re.search("^PUT", xml)):
				self.method = "PUT"
				try:
					req_xml = parse("./PSIA/" + self.messageList[self.msgChoice.GetCurrentSelection()])
				except:
					print "The PUT message is empty"
					self.req.SetValue("")
				else:
					self.req.SetValue(req_xml.toxml())
			else:
				self.method = "GET"

			path = re.sub('_', '/', re.search("[GET|PUT]_(.*)\.xml", xml).group(1))

			http = re.search("(^http://.*?/)", self.target.GetValue()).group(1)
			
			url = http + path

			print url
			self.target.SetValue(url)

		else:
			req_xml = parse("./ONVIF/" + self.messageList[self.msgChoice.GetCurrentSelection()])

			self.req.SetValue(req_xml.toxml())


	def OnButtonClick(self, event):
		self.rsp.SetValue("")
		self.startButton.SetLabel("stop");
		self.SendReq();
		self.startButton.SetLabel("start");
		event.Skip();

	def SendReq(self):
		req = urllib2.Request(self.target.GetValue())
		
		req.add_data(self.req.GetValue())
		if self.protocol.GetSelection() == 0:	#PSIA
			req.get_method = lambda: self.method

		try:
			handle = urllib2.urlopen(req);
		except IOError, e:
			print e.code
			print e.headers['www-authenticate']
		else:
			rsp_xml = parseString(handle.read())
			self.rsp.SetValue(rsp_xml.toprettyxml("  ", "\n"))

		chaldict = digest_auth.fetch_challenge(e.headers['www-authenticate'])
		
		if digest_auth.dict_fetch(chaldict, 'challenge', '').lower() == 'digest':
			authdict = digest_auth.generate_response(chaldict, urlparse(req.get_full_url())[2],
							self.user.GetValue(), self.passwd.GetValue(), method=req.get_method())
			headers = {\
				'Authorization':digest_auth.build_authorization_arg(authdict),
			}
		
		req.add_header('Authorization', digest_auth.build_authorization_arg(authdict))

		try:
			handle = urllib2.urlopen(req);
		except IOError, e:
			print e.code
			self.rsp.SetValue(e.read())
		else:
			rsp_xml = parseString(handle.read())
			self.rsp.SetValue(rsp_xml.toprettyxml("  ", "\n"))


if __name__=='__main__':
	app = wx.PySimpleApp()
	Frame().Show()
	app.MainLoop()




